#include "../include/engine/system.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <dirent.h>
#include <errno.h>
#include "../include/engine/graphics.h"
#include "../include/engine/control.h"
#include "../include/modules/coordinates.h"
#include "../include/modules/square.h"
#include "../include/modules/tower.h"
#include "../include/modules/monster.h"
#include "../lib/GM/include/list.h"

static const unsigned int BIT_PER_PIXEL = 32;
static Uint32 FRAMERATE_MILLISECONDS = 1000 / 10;
static float abscissaR = 2.0;
static float abscissaL = -2.0;
static float orderedU = 1.5;
static float orderedD = -1.5;
static GameState game = MENU;

void reshape(unsigned int w_width, unsigned int w_height){
    glViewport(0, 0, w_width, w_height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(abscissaL, abscissaR, orderedD, orderedU);
}

void setVideoMode(unsigned int w_width, unsigned int w_height){
    if(NULL == SDL_SetVideoMode(w_width, w_height, BIT_PER_PIXEL, SDL_OPENGL | SDL_RESIZABLE | SDL_GL_DOUBLEBUFFER)) {
        fprintf(stderr, "setVideoMode::Impossible d'ouvrir la fenetre. Fin du programme.\n");
        exit(EXIT_FAILURE);
    }
    reshape(w_width, w_height);
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 0);
    glClear(GL_COLOR_BUFFER_BIT);
    SDL_GL_SwapBuffers();
    glMatrixMode(GL_MODELVIEW);
}

int ImacTowerDefense(char *pathITD){
    //////////////////////////////////////////////
    // Définition des variables                 //
    // necessaire à l'initialisation du moteur. //
    //////////////////////////////////////////////
    int replay = 0;
    // Création des objets necessaire à la création de la Map
    Itd itd;
    char pathMap[60] = "images/\0";
    // Création du joueur
    Player *player;
    player = createPlayer();
    initPlayer(player);
    // Création variables necessaire à la SDL
    int loop = 1;
    SDL_Event event;
    // Création des variables SDL_Surface et des Textures
    int nbPathMonster = 4;
    int nbPathTower = 4;
    char *pathMonster[nbPathMonster];
    char *pathTower[nbPathTower];
    char *pathMenu;
    char *pathWin;
    char *pathLoose;

    pathMonster[0] = "./images/baby.png";
    pathMonster[1] = "./images/quinn.png";
    pathMonster[2] = "./images/joker.png";
    pathMonster[3] = "./images/captain.png";
    pathTower[0] = "./images/rocketTower.png";
    pathTower[1] = "./images/hybridTower.png";
    pathTower[2] = "./images/laserTower.png";
    pathTower[3] = "./images/machineGunTower.png";
    pathMenu = "./images/menu.png";
    pathWin = "./images/win.png";
    pathLoose = "./images/loose.png";

    SDL_Surface* imageMonster[nbPathMonster];
    SDL_Surface* imageTower[nbPathTower];
    SDL_Surface* imageMenu;
    SDL_Surface* imageWin;
    SDL_Surface* imageLoose;

    GLuint textureMap;
    GLuint textureMonster[nbPathMonster];
    GLuint textureTower[nbPathTower];
    GLuint textureMenu;
    GLuint textureWin;
    GLuint textureLoose;

    // Création des éléments ATB
    TwBar *welcomeMenu = NULL;
    TwBar *rulesMenu = NULL;
    TwBar *menu = NULL;
    TwBar *twMonster = NULL;
    TwBar *twTower = NULL;
    TwBar *lastMenu = NULL;

    MenuITD *menuItd = NULL;
    Tools* tools = NULL;

    // Liste des ITDS
    List itds = NULL;
    // Map
    Map *map = NULL;
    // Liste de Monstres.
    List listMonster = NULL;
    // Liste de Tours.
    List listTower = NULL;

    //////////////////////////////////
    // Initialisation SDL et OPENGL //
    //////////////////////////////////
    //On test si SDL est bien définit, puis on l'initialise.
    if(-1 == SDL_Init(SDL_INIT_VIDEO)) {
        fprintf(stderr, "Impossible d'initialiser la SDL. Fin du programme.\n");
        return EXIT_FAILURE;
    }
    //On lance la fenêtre SDL et le contexte OpenGL
    setVideoMode(player->param.w_width, player->param.w_height);
    //On nomme notre fenêtre
    SDL_WM_SetCaption("Imac Tower Defense GM", NULL);

    ////////////////////////////////
    // Initialisation AntTweakBar //
    ////////////////////////////////
    initAntTwBar(player->param.w_width, player->param.w_height);

    ///////////////////////
    // Chargement Images //
    ///////////////////////
    // Images Monstres
    for(int i = 0; i<nbPathMonster; i++){
        imageMonster[i] = IMG_Load(pathMonster[i]);
    }
    // Images Tower
    for(int i = 0; i<nbPathTower; i++){
        imageTower[i] = IMG_Load(pathTower[i]);
    }
    imageMenu = IMG_Load(pathMenu);
    imageWin = IMG_Load(pathWin);
    imageLoose = IMG_Load(pathLoose);
    if(imageMonster == NULL || imageTower == NULL || imageMenu == NULL || imageWin == NULL || imageLoose == NULL){
        fprintf(stderr,"Erreur, une image n'a pas été correctement chargée.\n");
    }

    //////////////////////////////////////////////////////////
    // Création des TEXTURES MONSTER et des TEXTURES TOWERS //
    //////////////////////////////////////////////////////////
    /* On créer les textures */
    for(int i = 0; i<nbPathMonster; i++){
        textureMonster[i] = createTexture(textureMonster[i], imageMonster[i]);
    }
    for(int i = 0; i<nbPathTower; i++){
        textureTower[i] = createTexture(textureTower[i], imageTower[i]);
    }
    textureMenu = createTexture(textureMenu, imageMenu);
    textureWin = createTexture(textureWin, imageWin);
    textureLoose = createTexture(textureLoose, imageLoose);

    /* Free les images SDL_Surface de la RAM*/
    for(int i = 0; i<nbPathMonster; i++){
        SDL_FreeSurface(imageMonster[i]);
    }
    for(int i = 0; i<nbPathTower; i++){
        SDL_FreeSurface(imageTower[i]);
    }
    SDL_FreeSurface(imageMenu);
    SDL_FreeSurface(imageWin);
    SDL_FreeSurface(imageLoose);

    // On fixe les couleurs de transparence
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);

    if(pathITD != NULL){
        // On créer notre Objet ITD à partir du fichier .itd.
        itd = checkItd(pathITD);

        /* On recupere le nom de la carte */
        strcat(pathMap, itd.carte);
        printf("chemin carte :%s\n", pathMap);
        /* Appel initMap() qui initialise la map pour jouer. */
        map = init(player, map, pathMap, itd, &textureMap);

        game = GAME;
    }
    ////////////////////////////////
    // Lancement du moteur de jeu //
    ////////////////////////////////
    // On lance la fonction play qui lance la boucle SDL du jeu
    play(&replay, &loop, &event, pathITD, tools, menuItd, &welcomeMenu, &rulesMenu, &menu, &twTower, &twMonster, &lastMenu, itd, player, map, &itds, &listMonster, &listTower, &textureMap, textureMonster, textureTower, &textureMenu, &textureWin, &textureLoose);

    // On free les pointeurs et on sort proprement du jeu.
    exitClean(&itds, &listMonster, &listTower, &textureMap, textureMonster, textureTower, &textureMenu, &textureWin, &textureLoose, player, map, &lastMenu, &twTower, &twMonster,&menu, &welcomeMenu, &rulesMenu);

    game = MENU;
    return replay;
}

Map* init(Player *player, Map *map, char *pathMap, Itd itd, GLuint *textureMap){
    //////////////////////////////////////////////
    // Définition des variables                 //
    // necessaire à l'initialisation de la map  //
    //////////////////////////////////////////////
    SDL_Surface* imageMap;

    /////////////////////////////////////////////
    // Image, TabNode, TabConstruct & Textures //
    /////////////////////////////////////////////
    //Image Map
    imageMap = IMG_Load(pathMap);

    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // Construction des tableaux nodes & Square pour construire la map puis remplacement de la couleur construct //
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /* Création du tableau de Square (carré) */
    int k = 0;
    int nbFragSquare = 40; // nb de pixels dans un carré attention choisir une valeur multiple de la taille total.
    if(player->param.w_height%nbFragSquare != 0){
        fprintf(stderr, "Erreur le nombre de Square n'est pas entier par rapport à la taille de la map.\n");
        fprintf(stderr, "Fixé à 24 automatiquement.\n");
        nbFragSquare = 24;
    }
    float lenghtSquareGL = SDLtoOpenGL(nbFragSquare, player->param.w_height, ORDERED); // taille en OpenGL d'un coté d'un carré.
    int nbSquare = ((player->param.w_height)/nbFragSquare)*((player->param.w_height)/nbFragSquare); // calcul du nombre de carré par rapport au repère OpenGL (plus précisémment la map).
    Square *squareTab = (Square *)malloc(sizeof(Square)*nbSquare); // Malloc du squareTab pour le garder en mémoire.
    if(squareTab == NULL){
        fprintf(stderr, "system:: squareTab n'a pas été malloc\n");
    }

    for(float xFirstFrag=-2; xFirstFrag<1.0-EPSILON; xFirstFrag += lenghtSquareGL){  // X
        for(float yFirstFrag=-1.5; yFirstFrag<1.5-EPSILON; yFirstFrag += lenghtSquareGL){  // Y !! Sens de dessin influ dans le parcours des fragments qui vont de -1.5 à 1.5 exclu.
            squareTab[k++] = createSquare(xFirstFrag, yFirstFrag, nbFragSquare, lenghtSquareGL);  // tableau des carrés.
        }
    }

    // Permet de récupérer les zones constructibles et remplir le squareTab.
    setConstructMap(imageMap, squareTab, player->param.w_height,player->param.w_width, nbSquare); //Remplir les coordonnées des zones constructible en coord SDL.
    // Permet de remplir la disponibilité de chauque square dans le tableau squareTab.
    fulfillSquareConstruct(squareTab, nbSquare);

    /* Création du tableau de noeuds */
    // On change le repere des coordonnées des noeuds
    for(int i=0; i<itd.nbNodes; i++){
        itd.nodes[i] = changeCoordMark(itd.nodes[i], player->param.w_height,player->param.w_width, imageMap->w, imageMap->h);
        if(itd.nodes[i].x < 0 || itd.nodes[i].x > 721 || itd.nodes[i].y < 0 || itd.nodes[i].y > 721){ // Vérification que les noeuds sont bien dans la map.
            fprintf(stderr, "system:: Un des noeuds n'est pas compris dans la map, veuillez verifier votre fichier .itd\n");
            exit(1);
        }
    }
    int nbNodes = itd.nbNodes;
    CoordOpenGL *nodesGL = (CoordOpenGL *)malloc(sizeof(CoordOpenGL)*nbNodes);
    if(nodesGL == NULL){
        fprintf(stderr, "system:: nodesGL n'a pas été malloc\n");
    }
    // On converti les coordonnées SDL en coordonnées OpenGL
    for(int i=0; i<nbNodes; i++){
        nodesGL[i] = coordSDLtoCoordOpenGL(itd.nodes[i], player->param.w_height,player->param.w_width);
    }

    /* On remplace la couleur de l'image dans la SDL_Surface de la map */
    colorMap(imageMap, itd);

    // On créer la texture de la map
    *textureMap = createTexture(*textureMap, imageMap);
    // On free la SDL_Surface de la map
    SDL_FreeSurface(imageMap);

    /////////////////////
    // Création de MAP //
    /////////////////////
    // Création de la Map.
    float heightMapGL, widthMapGL;
    heightMapGL = orderedU - orderedD;
    widthMapGL = abscissaR - abscissaL;
    map = createMap();  
    map = initMap(map, pathMap, textureMap, nbNodes, nodesGL, nbSquare, squareTab, player->param.w_width, player->param.w_height, widthMapGL, heightMapGL);

    return map;
}

void idle(Player *player, Map *map, List *listM, List *listT, GLuint *textureMonster, GLuint *textureTower, TwBar **twMonster){
    //Gere les vagues des monstres si l'utilisateur est trop long et ne fait pas appel à la vague
    if((winWave(*listM) == 1 && map->wave==10) || player->lvl == 0){
        player->gameTimer--;
        if(player->gameTimer == 0){
            player->lvl++;
            map->wave = 0;
        }
    }
    else{
        player->gameTimer = 600;
    }
    
    //Gere les vagues des monstres
    if(waveMonster(player, map, listM, textureMonster)){
        game = WIN;
    } 
    

    // Gere de deplacement des monstres
    foreachList(node, *listM){ // Ne pas oublier le cast du type générique (void *) -> (Monster *) pour l'utiliser.
        if(routeWay(node->data, map->nbNodes,  map->nodesGL)){
            game = LOOSE;
        }
        Monster *monster = (Monster *)node->data;
        if(monster->select == 1){
            positionPopUpMonster(monster, *twMonster, player->param.w_height, player->param.w_width);
        }
    }
    // Met a jour le monstre pris pour cible par une tour
    foreachList(node, *listT){
        Tower *t = (Tower *)node->data;
        updateTarget(t, *listM);
        if(shootMonster(t)){    // Verifie si le monstre est mort apres un shoot
            t->target.monster = NULL;
            t->target.distanceMtoT = 0;
        }
    }
    foreachList(node, *listM){  // Tue les monstres qui ont une vie null ou négatif.
        *listM = dieMonster(*listM, player, twMonster);
    }
}

void play(int *replay, int *loop, SDL_Event *e, char* pathITD, Tools* tools, MenuITD *menuItd, TwBar **welcomeMenu, TwBar **rulesMenu, TwBar **menu, TwBar **twTower, TwBar **twMonster, TwBar **lastMenu, Itd itd, Player *player, Map *map, List *itds, List *listM, List *listT, GLuint *textureMap, GLuint *textureMonster, GLuint *textureTower, GLuint *textureMenu, GLuint *textureWin, GLuint *textureLoose){
	int handled;
    int start;
    //Lancement de la boucle du moteur du jeu .
	while(*loop){
		Uint32 startTime = SDL_GetTicks();

        switch(game){
            case MENU:
                if(map == NULL){
                    if(*welcomeMenu == NULL){
                        start = 0;
                        *itds = getItds();
                        menuItd = initMenuITD(*itds);

                        // Création du menu Rules.
                        createTwBar(rulesMenu, "rulesMenu");
                        TwDefine(" rulesMenu help='rules\n' size='500 200' position='230 50' fontresizable=false iconified=true contained=true iconifiable=true iconpos=topleft text=dark color='150 255 150' alpha=230 ");
                        // Remplissage du menu rule.
                        setRulesMenu(*rulesMenu);
                        // Création du menu d'accueil.
                        createTwBar(welcomeMenu, "welcomeMenu");
                        TwDefine(" welcomeMenu help='Menu accueil\n' size='300 170' position='360 300' resizable=false movable=false fontresizable=false contained=true iconifiable=false iconpos=topleft text=dark color='150 255 150' alpha=230 ");
                        // Remplissage du menu d'accueil.
                        setWelcomeMenu(*welcomeMenu, *rulesMenu, menuItd, loop, &start);
                    }
                    if(start == 1 && strstr(menuItd->itd,"None") == NULL){
                        pathITD = menuItd->itd;
                    }
                    if(pathITD != NULL){
                        char pathMap2[60] = "images/\0";
                        char pathITD2[60] = "data/\0";
                        strcat(pathITD2, pathITD);
                        // On créer notre Objet ITD à partir du fichier .itd.
                        itd = checkItd(pathITD2);

                        /* On recupere le nom de la carte */
                        strcat(pathMap2, itd.carte);
                        printf("chemin carte :%s\n", pathMap2);
                        /* Appel initMap() qui initialise la map pour jouer. */
                        map = init(player, map, pathMap2, itd, textureMap);
                    }
                }
                /////////////
                // DESSINS //
                /////////////
                // Nettoyage du framebuffer
                glClear(GL_COLOR_BUFFER_BIT);
                glMatrixMode(GL_MODELVIEW);
                glLoadIdentity();
                glColor3ub(255, 255, 255);
                glEnable(GL_TEXTURE_2D);
                glBindTexture(GL_TEXTURE_2D, *textureMenu);
                    glBegin(GL_QUADS);
                        //coord
                        glTexCoord2f(0, 0);
                        glVertex2f(-2, 1.5);
                        glTexCoord2f(1, 0);
                        glVertex2f(2, 1.5);
                        glTexCoord2f(1, 1);
                        glVertex2f(2, -1.5);
                        glTexCoord2f(0, 1);
                        glVertex2f(-2, -1.5);
                    glEnd();
                glBindTexture(GL_TEXTURE_2D, 0);
                glDisable(GL_TEXTURE_2D);
                glDisable(GL_ALPHA_TEST);
                // Draw tweak bars
                TwDraw();
                SDL_GL_SwapBuffers();

                ////////////////
                // EVENEMENTS //
                ////////////////
                while(SDL_PollEvent(e)){
                    // Send event to AntTweakBar
                    handled = TwEventSDL(e, SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
                    // Use SDL normal function
                    if(!handled){
                        switch((*e).type){
                            case SDL_QUIT:
                                *loop = 0;
                                break;
                            case SDL_VIDEORESIZE:
                                resize(e->resize.w, e->resize.h, player);
                                setVideoMode(player->param.w_width, player->param.w_height);
                                break;
                            case SDL_KEYDOWN:
                                switch(e->key.keysym.sym){
                                    case SDLK_q : 
                                    case SDLK_ESCAPE : 
                                        quit(loop);
                                        break;
                                    default :
                                        break;
                                }
                                break;
                            default :
                                break;
                        }
                    }
                }
                if(map != NULL){
                    TwDeleteBar(*welcomeMenu);
                    *welcomeMenu = NULL;
                    TwDeleteBar(*rulesMenu);
                    *rulesMenu = NULL;
                    game = GAME;
                }
                break;
            case GAME:
                if(*menu == NULL){
                    createTwBar(menu, "Menu");
                    TwDefine(" Menu help='Game Menu\n' alwaysbottom=true resizable=false movable=false fontresizable=false contained=true iconifiable=false valueswidth=100 iconpos=topleft color='230 220 140' alpha=150 ");

                    tools = initTools(textureTower, textureMonster, listT, listM, player, map, *menu, *twMonster, twTower, loop, replay);

                    positionTwBar(player->param.w_width, *menu);
                    sizeTwBar(player->param.w_width, player->param.w_height, *menu);
                    setMainMenu(*menu, loop, tools);
                }
                /////////////
                // DESSINS //
                /////////////
                // Nettoyage du framebuffer
                glClear(GL_COLOR_BUFFER_BIT);

                // Gestion des dessins depuis Graphics.c
                drawAll(itd, map, listM, listT, player);

                // Draw tweak bars
                TwDraw();
                SDL_GL_SwapBuffers();

                ///////////
                // PAUSE //
                ///////////
                // Gère la pause entre les dessins et les évènement pour mettre à jour l'affichage avant la pause.
                if(map->pause == 1){
                    pause(loop);
                    map->pause = 0;
                }

                ////////////////
                // EVENEMENTS //
                ////////////////
                //Gestion des évènements depuis Control.c
                event(*e, loop, *menu, twTower, twMonster, player, map, listM, listT, tools);

                //Gère les mouvements en continu du jeu.
                idle(player, map, listM, listT, textureMonster, textureTower, twMonster);

                break;
            case WIN:
                if(*menu){
                    TwDeleteBar(*menu);
                    *menu = NULL;
                }
                if(*twTower){
                    TwDeleteBar(*twTower);
                    *twTower = NULL;
                }
                if(*twMonster){
                    TwDeleteBar(*twMonster);
                    *twMonster = NULL;
                }
                if(*lastMenu == NULL){
                    // Création du menu Rules.
                    createTwBar(lastMenu, "Bravo");
                    TwDefine(" Bravo size='300 200' position='330 250' fontsize=3 fontresizable=false contained=true iconifiable=false iconpos=topleft text=dark color='255 255 255' alpha=240 ");
                    // Remplissage du menu rule.
                    setLastMenu(*lastMenu, tools);
                }
                /////////////
                // DESSINS //
                /////////////
                // Nettoyage du framebuffer
                glClear(GL_COLOR_BUFFER_BIT);
                glMatrixMode(GL_MODELVIEW);
                glLoadIdentity();
                glColor3ub(255, 255, 255);
                glEnable(GL_TEXTURE_2D);
                glBindTexture(GL_TEXTURE_2D, *textureWin);
                    glBegin(GL_QUADS);
                        //coord
                        glTexCoord2f(0, 0);
                        glVertex2f(-2, 1.5);
                        glTexCoord2f(1, 0);
                        glVertex2f(2, 1.5);
                        glTexCoord2f(1, 1);
                        glVertex2f(2, -1.5);
                        glTexCoord2f(0, 1);
                        glVertex2f(-2, -1.5);
                    glEnd();
                glBindTexture(GL_TEXTURE_2D, 0);
                glDisable(GL_TEXTURE_2D);
                glDisable(GL_ALPHA_TEST);
                // Draw tweak bars
                TwDraw();
                SDL_GL_SwapBuffers();

                ////////////////
                // EVENEMENTS //
                ////////////////
                while(SDL_PollEvent(e)){
                    // Send event to AntTweakBar
                    handled = TwEventSDL(e, SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
                    // Use SDL normal function
                    if(!handled){
                        switch((*e).type){
                            case SDL_QUIT:
                                *loop = 0;
                                break;
                            case SDL_VIDEORESIZE:
                                resize(e->resize.w, e->resize.h, player);
                                setVideoMode(player->param.w_width, player->param.w_height);
                                break;
                            case SDL_KEYDOWN:
                                switch(e->key.keysym.sym){
                                    case SDLK_q : 
                                    case SDLK_ESCAPE : 
                                        quit(loop);
                                        break;
                                    default :
                                        break;
                                }
                                break;
                            default :
                                break;
                        }
                    }
                }
                break;
            case LOOSE:
                if(*menu){
                    TwDeleteBar(*menu);
                    *menu = NULL;
                }
                if(*twTower){
                    TwDeleteBar(*twTower);
                    *twTower = NULL;
                }
                if(*twMonster){
                    TwDeleteBar(*twMonster);
                    *twMonster = NULL;
                }
                if(*lastMenu == NULL){
                    // Création du menu Rules.
                    createTwBar(lastMenu, "GameOver");
                    TwDefine(" GameOver size='300 200' position='330 250' fontsize=3 fontresizable=false contained=true iconifiable=false iconpos=topleft text=dark color='255 255 255' alpha=240 ");
                    // Remplissage du menu rule.
                    setLastMenu(*lastMenu, tools);
                }
                /////////////
                // DESSINS //
                /////////////
                // Nettoyage du framebuffer
                glClear(GL_COLOR_BUFFER_BIT);
                glMatrixMode(GL_MODELVIEW);
                glLoadIdentity();
                glColor3ub(255, 255, 255);
                glEnable(GL_TEXTURE_2D);
                glBindTexture(GL_TEXTURE_2D, *textureLoose);
                    glBegin(GL_QUADS);
                        //coord
                        glTexCoord2f(0, 0);
                        glVertex2f(-2, 1.5);
                        glTexCoord2f(1, 0);
                        glVertex2f(2, 1.5);
                        glTexCoord2f(1, 1);
                        glVertex2f(2, -1.5);
                        glTexCoord2f(0, 1);
                        glVertex2f(-2, -1.5);
                    glEnd();
                glBindTexture(GL_TEXTURE_2D, 0);
                glDisable(GL_TEXTURE_2D);
                glDisable(GL_ALPHA_TEST);
                // Draw tweak bars
                TwDraw();
                SDL_GL_SwapBuffers();

                ////////////////
                // EVENEMENTS //
                ////////////////
                while(SDL_PollEvent(e)){
                    // Send event to AntTweakBar
                    handled = TwEventSDL(e, SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
                    // Use SDL normal function
                    if(!handled){
                        switch((*e).type){
                            case SDL_QUIT:
                                *loop = 0;
                                break;
                            case SDL_VIDEORESIZE:
                                resize(e->resize.w, e->resize.h, player);
                                setVideoMode(player->param.w_width, player->param.w_height);
                                break;
                            case SDL_KEYDOWN:
                                switch(e->key.keysym.sym){
                                    case SDLK_q : 
                                    case SDLK_ESCAPE : 
                                        quit(loop);
                                        break;
                                    default :
                                        break;
                                }
                                break;
                            default :
                                break;
                        }
                    }
                }
                break;
            default:
                break;
        }

        ///////////
		// Timer //
        ///////////
		Uint32 elapsedTime = SDL_GetTicks() - startTime;
		if(elapsedTime < FRAMERATE_MILLISECONDS){
			SDL_Delay(FRAMERATE_MILLISECONDS - elapsedTime);
		}
    }
}

void resize(int w, int h, Player *player){
    player->param.w_height = h;
    player->param.w_width = w;
}

int fastForward(){
    if(FRAMERATE_MILLISECONDS == (1000/10)){
        FRAMERATE_MILLISECONDS = 5 / 10;
        return 1;
    }
    else{
        FRAMERATE_MILLISECONDS = 1000 / 10;
        return 0;
    }
    return -1;
}

void pause(int *loop){
    int pause = 1;
    SDL_Event event;
    //Création de la boucle infini permettant la pause.
    do{
        while(SDL_PollEvent(&event)){
            switch(event.type){
                case SDL_QUIT:
                    pause = 0;
                    *loop = 0;
                    break;
                case SDL_KEYDOWN:
                    switch(event.key.keysym.sym){
                        case SDLK_p:
                            pause = 0;
                            break;
                        default :
                            break;
                    }
                    break;
                default :
                    break;
            }
        }
    } while(pause);
}

List getItds(){
    DIR* dir = opendir("./data");
    struct dirent* file;
    List itds = NULL;

    if(dir == NULL){
        fprintf(stderr, "Impossible d'ouvrir le dossier data.\n");
        perror("Erreur : ");
        exit(1);
    }

    char *none = (char *)malloc(sizeof(char)*6);
    strcpy(none, "None\0");
    itds = appendList(itds, none);

    while((file = readdir(dir)) != NULL){
        if(strstr(file->d_name, ".itd") != NULL){
            char* itd = (char *)malloc(sizeof(char)*(strlen(file->d_name)+1));
            strcpy(itd, file->d_name);
            itds = appendList(itds, itd);
        }
    }
    closedir(dir);

    return itds;
}

int exitClean(List *itds, List *listM, List *listT, GLuint *textureMap, GLuint *textureMonster, GLuint *textureTower, GLuint *textureMenu, GLuint *textureWin, GLuint *textureLoose, Player *player, Map *map, TwBar **lastMenu, TwBar **twTower, TwBar **twMonster, TwBar **menu, TwBar **welcomeMenu, TwBar **rulesMenu){
    //////////////////////////////////////////////////////////////
    // Exit Clean, Free Textures, Free List & Free SDL_Surfaces //
    //////////////////////////////////////////////////////////////
    if(*welcomeMenu){
        TwDeleteBar(*welcomeMenu);
        *welcomeMenu = NULL;
    }
    if(*rulesMenu){
        TwDeleteBar(*rulesMenu);
        *rulesMenu = NULL;
    }
    if(*lastMenu){
        TwDeleteBar(*lastMenu);
        *lastMenu = NULL;
    }
    if(*menu){
        TwDeleteBar(*menu);
        *menu = NULL;
    }
    if(*twTower){
        TwDeleteBar(*twTower);
        *twTower = NULL;
    }
    if(*twMonster){
        TwDeleteBar(*twMonster);
        *twMonster = NULL;
    }

    if(map != NULL){
        if(map->squareTab != NULL){
            /* Free squareTab */
            free(map->squareTab);
        }
        if(map->nodesGL != NULL){
            /* Free nodesGL */
            free(map->nodesGL);
        }
        /* Free Map */
        free(map);
        map = NULL;
    }
    
    if(player != NULL){
        /* Free Player */
        free(player);
        player = NULL;
    }
    
    /* Free les listes */
    if(*listT != NULL){
        freeList(*listT);
    }
    if(*listM != NULL){
        freeList(*listM);
    }  

    /* Free les textures */ 
    if(textureMap != NULL){
        glDeleteTextures(1, textureMap);
    }
    if(&(textureMonster[0]) != NULL){
        glDeleteTextures(1, &(textureMonster[0]));
        glDeleteTextures(1, &(textureMonster[1]));
        glDeleteTextures(1, &(textureMonster[2]));
        glDeleteTextures(1, &(textureMonster[3]));
    }       
    if(&(textureTower[0]) != NULL){
        glDeleteTextures(1, &(textureTower[0]));
        glDeleteTextures(1, &(textureTower[1]));
        glDeleteTextures(1, &(textureTower[2]));
        glDeleteTextures(1, &(textureTower[3]));
    }
    // Free TweakBar elements and stop AntTweakBar
    TwTerminate();
    printf("Sortie propre.\n");
    SDL_Quit();

    return EXIT_SUCCESS;
}

void quit(int *l){
    *l = 0;
}